#include "FramePool.hxx"
#include "Sequence.hxx"
#include "VideoThread.hxx"
#include "TrackedObject.hxx"
#include "Project.hxx"
#include "VideoView.hxx"

#include "YOLODetectingThread.hxx"

#include "json.hpp"

using json = nlohmann::json;
extern json __appSetting;

YOLODetectingThread::YOLODetectingThread()
{
}

YOLODetectingThread::~YOLODetectingThread()
{
}

void YOLODetectingThread::initialize()
{
	TrackingThread::initialize();

	std::wstring fileName;

	for (auto& tracker : __appSetting["trackers"]) {
		std::string val = tracker["name"];
		if (strcmp(val.c_str(), _modelType) == 0)
		{
			std::string val = tracker["file"];
			fileName = L"onnx/" + std::wstring(val.begin(), val.end());;
		}
	}
    _detector.setModelFile(fileName);
    _detector.initialize();
}

void YOLODetectingThread::run()
{
    std::vector<DetectedObject> detectedObjects;

	if (!isInitialized())
		initialize();

	Sequence* model = getSequence();
	Project* project = model->getVideoView()->getProject();

	while (1)
	{
		if (getStatus() == TR_STATUS_STOPPED) break;

		if (getStatus() == TR_STATUS_STOPPING)
		{
			setStatus(TR_STATUS_STOPPED);
			break;
		}

		FramePool* inputPool = getInputPool();
		FramePool* outputPool = getOutputPool();
		Sequence* model = getSequence();
		char* frameBuffer = getFrameBuffer();

		if (inputPool->popFrame(frameBuffer))
		{
			int frameIndex = *(int*)frameBuffer;

			static int lastFrameIndex = frameIndex;

			if ((frameIndex < lastFrameIndex) || (frameIndex - lastFrameIndex != 1))
			{
				printf("Error!!!\n");
			}
			lastFrameIndex = frameIndex;

			if (getStatus() == TR_STATUS_TRACKING)
			{
				cv::Mat img(model->getVideoHeight(), model->getVideoWidth(), CV_8UC3, frameBuffer + sizeof(VideoFrameInfo));

				_detector.detect(img, detectedObjects);

				std::vector<TrackedObject*>* objects = model->getTrackingObjects();

				for (int i = 0; i < detectedObjects.size(); i++)
				{
					DetectedObject dobj = detectedObjects.at(i);

					cv::Rect2d rect = cv::Rect2d(dobj.x, dobj.y, dobj.width, dobj.height);

					TrackedObject* object = new TrackedObject();
					object->setTemplateBox(rect);
					
					object->setObjectId(i);
					object->setStartFrameIndex(frameIndex);
					object->setEndFrameIndex(frameIndex);
					object->setClassIndex(0);
					
					objects->push_back(object);

					Shape* shape = 0;
					ProjectType pt = model->getVideoView()->getProject()->getProjectType();

					if (pt == TYPE_RECTANGLE)
						shape = new ShapeRect(rect);
					else if (pt == TYPE_FISH)
						shape = new ShapeFish(rect);
					
					object->pushShape(frameIndex, shape);
				}
			}

			while (outputPool->isFull())
			{
				msleep(50);
			}

			if (!outputPool->pushFrame(frameBuffer))
			{
				msleep(20);
			}
		}
		else
		{
			msleep(20);
		}
	}
	setStatus(TR_STATUS_STOPPED);
}
